package cn.tedu.qxhouserent.passport.service.impl;

import cn.tedu.qxhouserent.commons.ex.ServiceException;
import cn.tedu.qxhouserent.commons.pojo.vo.PageData;
import cn.tedu.qxhouserent.commons.util.PageInfoToPageDataConverter;
import cn.tedu.qxhouserent.commons.web.ServiceCode;
import cn.tedu.qxhouserent.passport.mapper.AdminMapper;
import cn.tedu.qxhouserent.passport.mapper.AdminRoleMapper;
import cn.tedu.qxhouserent.passport.mapper.RoleMapper;
import cn.tedu.qxhouserent.passport.pojo.entity.Admin;
import cn.tedu.qxhouserent.passport.pojo.entity.AdminRole;
import cn.tedu.qxhouserent.passport.pojo.param.AdminAddNewParam;
import cn.tedu.qxhouserent.passport.pojo.param.AdminLoginInfoParam;
import cn.tedu.qxhouserent.passport.pojo.param.AdminUpdateInfoParam;
import cn.tedu.qxhouserent.passport.pojo.vo.AdminListItemVO;
import cn.tedu.qxhouserent.passport.pojo.vo.AdminStandardVO;
import cn.tedu.qxhouserent.passport.pojo.vo.RoleStandardVO;
import cn.tedu.qxhouserent.passport.security.AdminDetails;
import cn.tedu.qxhouserent.passport.service.AdminService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

import static cn.tedu.qxhouserent.commons.web.ServiceCode.*;

@Service
@Transactional
@Slf4j
public class AdminServiceImpl implements AdminService {
    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private AdminRoleMapper adminRoleMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Value("${qxhouserent.jwt.secret-key}")
    private String secretKey;

    @Value("${qxhouserent.jwt.duration-in-minute}")
    private Long durationInMinute;


    @Override
    public String login(AdminLoginInfoParam adminLoginInfoParam) {
        log.debug("开始处理【管理员登录】的业务，参数：{}",adminLoginInfoParam);
        //创建认证时所需的参数对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginInfoParam.getUsername(),
                adminLoginInfoParam.getPassword()
        );
        //执行认证, 并获取认证结果
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("验证登录成功!,认证结果:{}",authenticateResult);

        Object principal = authenticateResult.getPrincipal();
        AdminDetails adminDetails = (AdminDetails) principal;
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();

        Map<String,Object> claims = new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("username",adminDetails.getUsername());
        claims.put("authoritiesJsonString", JSON.toJSONString(authorities));

        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                //Payload
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000))
                // Verify Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                //生成
                .compact();

        log.debug("生成了管理员的信息对应的JWT: {}",jwt);
        return jwt;
        // 需要缓存到Redis中的数据
//        AdminLoginInfoPO adminLoginInfoPO = new AdminLoginInfoPO();
//        adminLoginInfoPO.setId(adminDetails.getId());
//        adminLoginInfoPO.setEnable(adminDetails.isEnabled() ? 1 : 0);
//        adminLoginInfoPO.setRemoteAddr(remoteAddr);
//        adminLoginInfoPO.setUserAgent(userAgent);
//        adminLoginInfoPO.setAuthorityListJsonString(JSON.toJSONString(adminDetails.getAuthorities()));
//        adminCacheRepository.saveLoginInfo(jwt, adminLoginInfoPO, tokenDuration);
//        log.debug("向Redis中写入此管理员的登录信息：{}", adminLoginInfoPO);
//
//        // 准备返回
//        AdminLoginInfoVO adminLoginInfoVO = new AdminLoginInfoVO()
//                .setId(adminDetails.getId())
//                .setUsername(adminDetails.getUsername())
//                .setAvatar(adminDetails.getAvatar())
//                .setToken(jwt)
//                .setTokenExpiration(tokenExpiration);
//        return adminLoginInfoVO;
    }



    //添加管理员
    @Override
    public void addNew(AdminAddNewParam adminAddNewParam) {
        log.debug("开始处理【添加管理员】业务：{}", adminAddNewParam);

        //查看管理员表中有无相同username的数据
        log.debug("查看管理员中有无相同username的数据：");
        QueryWrapper<Admin> AdminQueryWrapper = new QueryWrapper<>();
        AdminQueryWrapper.eq("username", adminAddNewParam.getUsername());
        Integer num = adminMapper.selectCount(AdminQueryWrapper);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同用户名的数据，添加失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //查看管理员表中有无相同phoneNumber的数据
        log.debug("查看管理员中有无相同phoneNumber的数据：");
        QueryWrapper<Admin> AdminQueryWrapper2 = new QueryWrapper<>();
        AdminQueryWrapper2.eq("phone_number", adminAddNewParam.getPhoneNumber());
        num = adminMapper.selectCount(AdminQueryWrapper2);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同电话号的数据，添加失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //查看idCard是否已经被其他管理员占用
        log.debug("查看idCard是否已经被其他管理员占用：");
        QueryWrapper<Admin> AdminQueryWrapper3 = new QueryWrapper<>();
        AdminQueryWrapper3.eq("id_card", adminAddNewParam.getIdCard());
        num = adminMapper.selectCount(AdminQueryWrapper3);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同身份证号的数据，添加失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //开始向admin中添加数据
        log.debug("检查通过！开始添加数据：{}", adminAddNewParam);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewParam, admin);
        admin.setGmtCreate(LocalDateTime.now());
        admin.setGmtModified(LocalDateTime.now());
        String rawPassword = admin.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodePassword);
        log.debug("插入数据为：{}", admin);

        int rows = adminMapper.insert(admin);
        if (rows != 1) {
            String message = "添加失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ERR_INSERT, message);
        }
        log.debug("插入后的数据为：{}", admin);

        Long[] roleIds = adminAddNewParam.getRoleIds();
        AdminRole[] adminRoles = new AdminRole[roleIds.length];
        LocalDateTime now = LocalDateTime.now();
        for (int i = 0; i < adminRoles.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(now);
            adminRole.setGmtModified(now);
            adminRoles[i] = adminRole;
        }
        rows = adminRoleMapper.insertBatch(adminRoles);
        if (rows != adminRoles.length){
            String message = "添加管理员失败,服务器正忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ERR_INSERT,message);
        }
        log.debug("将新的管理员与角色的关联数据插入到数据库,完成!");


        log.debug("添加成功！");
    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【根据ID删除管理员】的业务，参数：{}", id);
        // 检查该管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "删除管理员失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //删除管理员表
        int rows = adminMapper.deleteById(id);
        if (rows != 1) {
            String message = "删除失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ERR_DELETE, message);
        }

        //将原有admin_role关联删除
        QueryWrapper<AdminRole> adminRoleQueryWrapper = new QueryWrapper<>();
        adminRoleQueryWrapper.eq("admin_id", id);
        Integer integer = adminRoleMapper.selectCount(adminRoleQueryWrapper);

        if (integer != 0) {
            int i1 = adminRoleMapper.deleteByAdminId(id);
            if (i1 != integer) {
                String message = "删除失败，服务器忙，请稍后再试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        log.debug("删除成功！");
    }

    //修改管理员信息
    @Override
    public void updateById(Long id,AdminUpdateInfoParam adminUpdateInfoParam) {
        log.debug("开始处理【修改管理员】的业务，ID：{}, 新数据：{}", id, adminUpdateInfoParam);
        // 检查管理员是否存在，如果不存在，则抛出异常
        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = adminMapper.selectCount(queryWrapper);
        log.debug("根据管理员ID统计匹配的管理员数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改管理员信息失败，管理员数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //查看修改的username是否已经被其他管理员占用
        log.debug("查看修改的username是否已经被其他管理员占用：");
        QueryWrapper<Admin> AdminQueryWrapper = new QueryWrapper<>();
        AdminQueryWrapper.eq("username", adminUpdateInfoParam.getUsername())
                .ne("id", id);
        Integer num = adminMapper.selectCount(AdminQueryWrapper);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同用户名的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //查看修改的phoneNumber是否已经被其他管理员占用
        log.debug("查看修改的phoneNumber是否已经被其他管理员占用：");
        QueryWrapper<Admin> AdminQueryWrapper2 = new QueryWrapper<>();
        AdminQueryWrapper2.eq("phone_number", adminUpdateInfoParam.getPhoneNumber())
                .ne("id", id);
        num = adminMapper.selectCount(AdminQueryWrapper2);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同电话号的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //查看修改的idCard是否已经被其他管理员占用
        log.debug("查看修改的idCard是否已经被其他管理员占用：");
        QueryWrapper<Admin> AdminQueryWrapper3 = new QueryWrapper<>();
        AdminQueryWrapper3.eq("id_card", adminUpdateInfoParam.getIdCard())
                .ne("id", id);
        num = adminMapper.selectCount(AdminQueryWrapper3);
        log.debug("查询结果：{}", num);

        if (num > 0) {
            String message = "管理员表中有相同身份证号的数据，修改失败！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 执行修改
        log.debug("检查通过，开始修改！");
        String rawPassword = adminUpdateInfoParam.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        adminUpdateInfoParam.setPassword(encodePassword);
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminUpdateInfoParam, admin);
        admin.setId(id);
        admin.setGmtModified(LocalDateTime.now());
        int i = adminMapper.updateById(admin);
        if (i != 1) {
            String message = "更新失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }

        //将原有admin_role关联删除
        QueryWrapper<AdminRole> adminRoleQueryWrapper = new QueryWrapper<>();
        adminRoleQueryWrapper.eq("admin_id", id);
        Integer integer = adminRoleMapper.selectCount(adminRoleQueryWrapper);

        if (integer != 0) {
            int i1 = adminRoleMapper.deleteByAdminId(id);
            if (i1 != integer) {
                String message = "删除失败，服务器忙，请稍后再试！";
                log.warn(message);
                throw new ServiceException(ERR_DELETE, message);
            }
        }

        //新增admin_role新关联
        Long[] roleIds = adminUpdateInfoParam.getRoleIds();
        if (roleIds.length != 0) {
            AdminRole[] adminRoles = new AdminRole[roleIds.length];
            for (int j = 0; j < roleIds.length; j++) {
                AdminRole adminRole1 = new AdminRole();
                adminRole1.setAdminId(id)
                        .setRoleId(roleIds[j])
                        .setGmtCreate(LocalDateTime.now())
                        .setGmtModified(LocalDateTime.now());
                adminRoles[j] = adminRole1;
            }
            int i2 = adminRoleMapper.insertBatch(adminRoles);
            if (i2 != adminRoles.length) {
                String message = "添加失败，服务器忙，请稍后再试！";
                log.warn(message);
                throw new ServiceException(ERR_INSERT, message);
            }
        }


        log.debug("将新的管理员数据更新入到数据库，完成！");
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id, 1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id, 0);
    }

    private void updateEnableById(Long id, Integer enable) {
        log.debug("开始处理【{}管理员】的业务，ID：{}，目标状态：{}", ENABLE_TEXT[enable], id, enable);
        // 检查数据是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = ENABLE_TEXT[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND, message);
        }

        // 检查当前状态是否与参数表示的状态相同
        if (queryResult.getEnable().equals(enable)) {
            String message = ENABLE_TEXT[enable] + "管理员失败，当前管理员已经处于"
                    + ENABLE_TEXT[enable] + "状态！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }

        // 准备执行更新
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        log.debug("即将修改数据，参数：{}", admin);
        int rows = adminMapper.updateById(admin);
        if (rows != 1) {
            String message = ENABLE_TEXT[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE, message);
        }
    }

    //根据id查询管理员
    @Override
    public AdminStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询管理员】的业务，参数：{}", id);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        Long[] roleIds = adminRoleMapper.selectRoleIdsByAdminId(id);
        queryResult.setRoleIds(roleIds);
        List<String> roleNames = new ArrayList<>();
        for (Long roleId:roleIds){
            RoleStandardVO roleStandardVO = roleMapper.getStandardById(roleId);
            roleNames.add(roleStandardVO.getName());
        }
        queryResult.setRoleNames(roleNames);

        if (queryResult == null) {
            String message = "查询管理员失败，数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    //查询管理员列表
    @Override
    public PageData<AdminListItemVO> list(Integer pageNum) {
        Integer pageSize = 5;
        return list(pageNum,pageSize);
    }

    //查询管理员列表
    @Override
    public PageData<AdminListItemVO> list(Integer pageNum, Integer pageSize) {
        log.debug("开始处理【查询管理员列表】的业务，页码：{}，每页记录数：{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminListItemVO> list = adminMapper.list();
        PageInfo<AdminListItemVO> pageInfo = new PageInfo<>(list);
        PageData<AdminListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("查询完成，即将返回：{}", pageData);
        return pageData;
    }
}
